﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using AnthStat.Infrastructure;

namespace AnthStat.Domain
{
    public class XmlPersonRepository : EntityXmlRepository<Person>
    {
        protected override Func<XElement, Person> Selector
        {
            get
            {
                return x => CreatePerson(x);
            }
        }

        private static Person CreatePerson(XElement x)
        {
            Contract.Requires(x != null);
            Contract.Ensures(Contract.Result<Person>() != null);

            Person person = new Person(x.Attribute("Id").Value, DateTime.Parse(x.Attribute("DateCreated").Value, System.Globalization.CultureInfo.InvariantCulture), Int32.Parse(x.Attribute("NumericId").Value), null)
            {
                IsMeasureable = bool.Parse(x.Attribute("IsMeasureable").Value),
                DateUpdated = DateTime.Parse(x.Attribute("DateUpdated").Value, System.Globalization.CultureInfo.InvariantCulture),

                UserCreated = x.Attribute("UserCreated").Value,
                UserUpdated = x.Attribute("UserUpdated").Value,

                FirstName = x.Element("FirstName").Value,
                LastName = x.Element("LastName").Value,
                SexString = x.Element("Sex").Value,
                DateBirth = DateTime.Parse(x.Element("DateBirth").Value, System.Globalization.CultureInfo.InvariantCulture),
                IsDateBirthEstimated = Boolean.Parse(x.Element("IsDateBirthEstimated").Value),
                StreetAddress = x.Element("StreetAddress").Value,
                City = x.Element("City").Value,
                Adm1 = x.Element("Adm1").Value,
                Adm2 = x.Element("Adm2").Value,
                Adm3 = x.Element("Adm3").Value,
                PostalCode = x.Element("PostalCode").Value,
                Country = x.Element("Country").Value,
                HomePhoneNumber = x.Element("HomePhoneNumber").Value,
                WorkPhoneNumber = x.Element("WorkPhoneNumber").Value,
                CellPhoneNumber = x.Element("CellPhoneNumber").Value,
                Email = x.Element("Email").Value,
                Race = x.Element("Race").Value,
                Ethnicity = x.Element("Ethnicity").Value,

                Team = x.Element("Team").Value,
                Cluster = String.IsNullOrEmpty(x.Element("Cluster").Value) ? Int32.MinValue : Convert.ToInt32(x.Element("Cluster").Value),
                Household = x.Element("Household").Value
            };

            foreach (XElement element in x.Elements("Measurements").Elements("Measurement"))
            {
                person.AddMeasurement(CreateMeasurement(element, person));
            }

            return person;
        }

        private static Measurement CreateMeasurement(XElement x, Person person)
        {
            Contract.Requires(x != null);
            Contract.Requires(person != null);
            Contract.Ensures(Contract.Result<Measurement>() != null);

            var measurement = new Measurement(
                x.Attribute("Id").Value, 
                person, 
                DateTime.Parse(x.Attribute("DateCreated").Value, System.Globalization.CultureInfo.InvariantCulture), 
                DateTime.Parse(x.Element("DateMeasurement").Value, System.Globalization.CultureInfo.InvariantCulture))
            {
                IsDateMeasurementEstimated = Boolean.Parse(x.Element("IsDateMeasurementEstimated").Value),
                DateUpdated = DateTime.Parse(x.Attribute("DateUpdated").Value, System.Globalization.CultureInfo.InvariantCulture), 
                Notes = x.Element("Notes").Value,
                Location = x.Element("Location").Value
            };

            double ageDays;
            bool success = Double.TryParse(x.Element("AgeDays").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out ageDays);
            if (success)
            {
                measurement.AgeDays = ageDays;
            }

            double bmi;
            success = Double.TryParse(x.Element("BMI").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out bmi);
            if (success)
            {
                measurement.BodyMassIndex = bmi;
            }

            double height;
            success = Double.TryParse(x.Element("Ht").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out height);
            if (success)
            {
                measurement.Height = height;
            }

            double weight;
            success = Double.TryParse(x.Element("Wt").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out weight);
            if (success)
            {
                measurement.Weight = weight;
            }

            double headCircumference;
            success = Double.TryParse(x.Element("Hc").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out headCircumference);
            if (success)
            {
                measurement.HeadCircumference = headCircumference;
            }

            double armCircumference;
            success = Double.TryParse(x.Element("Muac").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out armCircumference);
            if (success)
            {
                measurement.MidUpperArmCircumference = armCircumference;
            }

            double subscapularSkinfold;
            success = Double.TryParse(x.Element("Ssf").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out subscapularSkinfold);
            if (success)
            {
                measurement.SubscapularSkinfold = subscapularSkinfold;
            }

            double tripcepsSkinfold;
            success = Double.TryParse(x.Element("Tsf").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out tripcepsSkinfold);
            if (success)
            {
                measurement.TricepsSkinfold = tripcepsSkinfold;
            }

            XElement cdcResultsElement = x.Element("CDCResults");
            measurement.AddCDCResults(CreateCDCResults(cdcResultsElement, measurement));

            XElement whoResultsElement = x.Element("WHOResults");
            measurement.AddWHOResults(CreateWHOResults(whoResultsElement, measurement));

            return measurement;
        }

        private static ResultsCDC CreateCDCResults(XElement x, Measurement measurement)
        {
            Contract.Requires(x != null);
            Contract.Requires(measurement != null);
            Contract.Ensures(Contract.Result<ResultsCDC>() != null);

            ResultsCDC results = new ResultsCDC(measurement);

            double bmiZ;
            double bmiP;
            double wtAgeZ;
            double wtAgeP;
            double htAgeZ;
            double htAgeP;
            double wtHtZ;
            double wtHtP;
            double hcZ;
            double hcP;

            // Body mass index for Age
            bool success = Double.TryParse(x.Element("BMIZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out bmiZ);
            if (success)
            {
                results.BMIForAgeZ = bmiZ;
            }

            success = Double.TryParse(x.Element("BMIP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out bmiP);
            if (success)
            {
                results.BMIForAgeP = bmiP;
            }

            // Height for Age
            success = Double.TryParse(x.Element("HAZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out htAgeZ);
            if (success)
            {
                results.StatureForAgeZ = htAgeZ;
            }

            success = Double.TryParse(x.Element("HAP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out htAgeP);
            if (success)
            {
                results.StatureForAgeP = htAgeP;
            }

            // Weight for Age
            success = Double.TryParse(x.Element("WAZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out wtAgeZ);
            if (success)
            {
                results.WeightForAgeZ = wtAgeZ;
            }

            success = Double.TryParse(x.Element("WAP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out wtAgeP);
            if (success)
            {
                results.WeightForAgeP = wtAgeP;
            }

            // Weight for Height
            success = Double.TryParse(x.Element("WHZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out wtHtZ);
            if (success)
            {
                results.WeightForStatureZ = wtHtZ;
            }

            success = Double.TryParse(x.Element("WHP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out wtHtP);
            if (success)
            {
                results.WeightForStatureP = wtHtP;
            }

            // Head circumference for age
            success = Double.TryParse(x.Element("HCAZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out hcZ);
            if (success)
            {
                results.HeadCircumferenceForAgeZ = hcZ;
            }

            success = Double.TryParse(x.Element("HCAP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out hcP);
            if (success)
            {
                results.HeadCircumferenceForAgeP = hcP;
            }

            return results;
        }

        private static ResultsWHO CreateWHOResults(XElement x, Measurement measurement)
        {
            Contract.Requires(x != null);
            Contract.Requires(measurement != null);
            Contract.Ensures(Contract.Result<ResultsWHO>() != null);

            ResultsWHO results = new ResultsWHO(measurement);

            double bmiZ;
            double bmiP;
            double wtAgeZ;
            double wtAgeP;
            double htAgeZ;
            double htAgeP;
            double wtHtZ;
            double wtHtP;
            double hcZ;
            double hcP;

            double ssfZ;
            double ssfP;
            double tsfZ;
            double tsfP;
            double muacZ;
            double muacP;

            // Body mass index for Age
            bool success = Double.TryParse(x.Element("BMIZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out bmiZ);
            if (success)
            {
                results.BMIForAgeZ = bmiZ;
            }

            success = Double.TryParse(x.Element("BMIP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out bmiP);
            if (success)
            {
                results.BMIForAgeP = bmiP;
            }

            // Height for Age
            success = Double.TryParse(x.Element("HAZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out htAgeZ);
            if (success)
            {
                results.StatureForAgeZ = htAgeZ;
            }

            success = Double.TryParse(x.Element("HAP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out htAgeP);
            if (success)
            {
                results.StatureForAgeP = htAgeP;
            }

            // Weight for Age
            success = Double.TryParse(x.Element("WAZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out wtAgeZ);
            if (success)
            {
                results.WeightForAgeZ = wtAgeZ;
            }

            success = Double.TryParse(x.Element("WAP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out wtAgeP);
            if (success)
            {
                results.WeightForAgeP = wtAgeP;
            }

            // Weight for Height
            success = Double.TryParse(x.Element("WHZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out wtHtZ);
            if (success)
            {
                results.WeightForStatureZ = wtHtZ;
            }

            success = Double.TryParse(x.Element("WHP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out wtHtP);
            if (success)
            {
                results.WeightForStatureP = wtHtP;
            }

            // Head circumference for age
            success = Double.TryParse(x.Element("HCAZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out hcZ);
            if (success)
            {
                results.HeadCircumferenceForAgeZ = hcZ;
            }

            success = Double.TryParse(x.Element("HCAP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out hcP);
            if (success)
            {
                results.HeadCircumferenceForAgeP = hcP;
            }

            // Subscapular skin fold for age
            success = Double.TryParse(x.Element("SSFAZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out ssfZ);
            if (success)
            {
                results.SSFForAgeZ = ssfZ;
            }

            success = Double.TryParse(x.Element("SSFAP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out ssfP);
            if (success)
            {
                results.SSFForAgeP = ssfP;
            }

            // Triceps skin fold for age
            success = Double.TryParse(x.Element("TSFAZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out tsfZ);
            if (success)
            {
                results.TSFForAgeZ = tsfZ;
            }

            success = Double.TryParse(x.Element("TSFAP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out tsfP);
            if (success)
            {
                results.TSFForAgeP = tsfP;
            }

            // Mid-upper arm circumference for age
            success = Double.TryParse(x.Element("MUACZ").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out muacZ);
            if (success)
            {
                results.MidUpperArmCircumferenceForAgeZ = muacZ;
            }

            success = Double.TryParse(x.Element("MUACP").Value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out muacP);
            if (success)
            {
                results.MidUpperArmCircumferenceForAgeP = muacP;
            }

            return results;
        }

        protected override XElement CreateXElement(Person model)
        {
            if (model == null) throw new ArgumentNullException("model");

            model.GlobalRecordId = Guid.NewGuid().ToString();

            XElement element = new XElement(ElementName,
                new XAttribute("Id", model.GlobalRecordId),
                new XAttribute("DateCreated", model.DateCreated.ToString("MM/dd/yyyy", System.Globalization.CultureInfo.InvariantCulture)),
                new XAttribute("DateUpdated", model.DateUpdated.ToString("MM/dd/yyyy", System.Globalization.CultureInfo.InvariantCulture)),
                new XAttribute("UserCreated", model.UserCreated),
                new XAttribute("UserUpdated", model.UserUpdated),
                new XAttribute("IsMeasureable", model.IsMeasureable),
                new XAttribute("NumericId", model.NumericId.ToString()),
                new XElement("FirstName", model.FirstName),
                new XElement("LastName", model.LastName),
                new XElement("Sex", model.Sex),
                new XElement("DateBirth", model.DateBirth.HasValue ? model.DateBirth.Value.ToString("MM/dd/yyyy", System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("IsDateBirthEstimated", model.IsDateBirthEstimated.ToString()),
                new XElement("StreetAddress", model.StreetAddress),
                new XElement("City", model.City),
                new XElement("Adm1", model.Adm1),
                new XElement("Adm2", model.Adm2),
                new XElement("Adm3", model.Adm3),
                new XElement("PostalCode", model.PostalCode),
                new XElement("Country", model.Country),
                new XElement("HomePhoneNumber", model.HomePhoneNumber),
                new XElement("WorkPhoneNumber", model.WorkPhoneNumber),
                new XElement("CellPhoneNumber", model.CellPhoneNumber),
                new XElement("Email", model.Email),
                new XElement("Race", model.Race),
                new XElement("Ethnicity", model.Ethnicity),

                new XElement("Team", model.Team),
                new XElement("Cluster", model.Cluster.ToString()),
                new XElement("Household", model.Household),


                new XElement("Measurements")
            );

            if (model.Measurements.Count() > 0)
            {
                XElement measurements = element.Element("Measurements");

                foreach (Measurement measurementModel in model.Measurements)
                {
                    measurements.Add(CreateMeasurementXElement(measurementModel));
                }
            }

            return element;
        }

        protected XElement CreateMeasurementXElement(Measurement model)
        {
            if (model == null) throw new ArgumentNullException("model");

            XElement element = new XElement("Measurement");

            element.Add(
                new XAttribute("Id", model.GlobalRecordId),
                new XAttribute("DateCreated", model.DateCreated.ToString("MM/dd/yyyy", System.Globalization.CultureInfo.InvariantCulture)),
                new XAttribute("DateUpdated", model.DateUpdated.ToString("MM/dd/yyyy", System.Globalization.CultureInfo.InvariantCulture)),

                new XElement("DateMeasurement", model.DateMeasurement.ToString("MM/dd/yyyy", System.Globalization.CultureInfo.InvariantCulture)),
                new XElement("IsDateMeasurementEstimated", model.IsDateMeasurementEstimated.ToString()),
                new XElement("IsRecumbent", model.IsRecumbent.ToString()),
                new XElement("HasOedema", model.HasOedema.ToString()),
                new XElement("AgeDays", model.AgeDays.ToString()),

                new XElement("BMI", model.BodyMassIndex.HasValue ? model.BodyMassIndex.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("Ht", model.Height.HasValue ? model.Height.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("Wt", model.Weight.HasValue ? model.Weight.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("Hc", model.HeadCircumference.HasValue ? model.HeadCircumference.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("Muac", model.MidUpperArmCircumference.HasValue ? model.MidUpperArmCircumference.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("Ssf", model.SubscapularSkinfold.HasValue ? model.SubscapularSkinfold.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("Tsf", model.TricepsSkinfold.HasValue ? model.TricepsSkinfold.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("Notes", model.Notes.ToString()),
                new XElement("Location", model.Location.ToString()),
                new XElement("CDCResults"),
                new XElement("WHOResults")
                );

            XElement resultsCDC = element.Element("CDCResults");

            resultsCDC.Add(
                new XElement("BMIZ", model.ResultsCDC.BMIForAgeZ.HasValue ? model.ResultsCDC.BMIForAgeZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("HAZ", model.ResultsCDC.StatureForAgeZ.HasValue ? model.ResultsCDC.StatureForAgeZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("WAZ", model.ResultsCDC.WeightForAgeZ.HasValue ? model.ResultsCDC.WeightForAgeZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("WHZ", model.ResultsCDC.WeightForStatureZ.HasValue ? model.ResultsCDC.WeightForStatureZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("HCAZ", model.ResultsCDC.HeadCircumferenceForAgeZ.HasValue ? model.ResultsCDC.HeadCircumferenceForAgeZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),

                new XElement("BMIP", model.ResultsCDC.BMIForAgeP.HasValue ? model.ResultsCDC.BMIForAgeP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("HAP", model.ResultsCDC.StatureForAgeP.HasValue ? model.ResultsCDC.StatureForAgeP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("WAP", model.ResultsCDC.WeightForAgeP.HasValue ? model.ResultsCDC.WeightForAgeP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("WHP", model.ResultsCDC.WeightForStatureP.HasValue ? model.ResultsCDC.WeightForStatureP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("HCAP", model.ResultsCDC.HeadCircumferenceForAgeP.HasValue ? model.ResultsCDC.HeadCircumferenceForAgeP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty)
                );

            XElement resultsWHO = element.Element("WHOResults");

            resultsWHO.Add(
                new XElement("BMIZ", model.ResultsWHO.BMIForAgeZ.HasValue ? model.ResultsWHO.BMIForAgeZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("HAZ", model.ResultsWHO.StatureForAgeZ.HasValue ? model.ResultsWHO.StatureForAgeZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("WAZ", model.ResultsWHO.WeightForAgeZ.HasValue ? model.ResultsWHO.WeightForAgeZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("WHZ", model.ResultsWHO.WeightForStatureZ.HasValue ? model.ResultsWHO.WeightForStatureZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("HCAZ", model.ResultsWHO.HeadCircumferenceForAgeZ.HasValue ? model.ResultsWHO.HeadCircumferenceForAgeZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("SSFAZ", model.ResultsWHO.SSFForAgeZ.HasValue ? model.ResultsWHO.SSFForAgeZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("TSFAZ", model.ResultsWHO.TSFForAgeZ.HasValue ? model.ResultsWHO.TSFForAgeZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("MUACZ", model.ResultsWHO.MidUpperArmCircumferenceForAgeZ.HasValue ? model.ResultsWHO.MidUpperArmCircumferenceForAgeZ.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),

                new XElement("BMIP", model.ResultsWHO.BMIForAgeP.HasValue ? model.ResultsWHO.BMIForAgeP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("HAP", model.ResultsWHO.StatureForAgeP.HasValue ? model.ResultsWHO.StatureForAgeP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("WAP", model.ResultsWHO.WeightForAgeP.HasValue ? model.ResultsWHO.WeightForAgeP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("WHP", model.ResultsWHO.WeightForStatureP.HasValue ? model.ResultsWHO.WeightForStatureP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("HCAP", model.ResultsWHO.HeadCircumferenceForAgeP.HasValue ? model.ResultsWHO.HeadCircumferenceForAgeP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("SSFAP", model.ResultsWHO.SSFForAgeP.HasValue ? model.ResultsWHO.SSFForAgeP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("TSFAP", model.ResultsWHO.TSFForAgeP.HasValue ? model.ResultsWHO.TSFForAgeP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty),
                new XElement("MUACP", model.ResultsWHO.MidUpperArmCircumferenceForAgeP.HasValue ? model.ResultsWHO.MidUpperArmCircumferenceForAgeP.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty)
                );

            return element;
        }

        protected override void SetXElementValue(Person model, XElement element)
        {
            if (model == null) throw new ArgumentNullException("model");
            if (element == null) throw new ArgumentNullException("element");

            Contract.Requires(model != null);
            Contract.Requires(element != null);
            Contract.Requires(model.Measurements != null);

            element.Attribute("Id").SetValue(model.GlobalRecordId);
            element.Attribute("DateCreated").SetValue(model.DateCreated.ToString(System.Globalization.CultureInfo.InvariantCulture));
            element.Attribute("DateUpdated").SetValue(model.DateUpdated.ToString(System.Globalization.CultureInfo.InvariantCulture));
            element.Attribute("UserCreated").SetValue(model.UserCreated);
            element.Attribute("UserUpdated").SetValue(model.UserUpdated);
            element.Attribute("IsMeasureable").SetValue(model.IsMeasureable);

            element.Element("FirstName").SetValue(model.FirstName);
            element.Element("LastName").SetValue(model.LastName);

            element.Element("Sex").SetValue(model.SexString);
            element.Element("DateBirth").SetValue(model.DateBirth.Value.ToString(System.Globalization.CultureInfo.InvariantCulture));
            element.Element("IsDateBirthEstimated").SetValue(model.IsDateBirthEstimated);
            element.Element("StreetAddress").SetValue(model.StreetAddress);
            element.Element("City").SetValue(model.City);
            element.Element("Adm1").SetValue(model.Adm1);
            element.Element("Adm2").SetValue(model.Adm2);
            element.Element("Adm3").SetValue(model.Adm3);
            element.Element("PostalCode").SetValue(model.PostalCode);
            element.Element("Country").SetValue(model.Country);
            element.Element("HomePhoneNumber").SetValue(model.HomePhoneNumber);
            element.Element("WorkPhoneNumber").SetValue(model.WorkPhoneNumber);
            element.Element("CellPhoneNumber").SetValue(model.CellPhoneNumber);
            element.Element("Email").SetValue(model.Email);
            element.Element("Race").SetValue(model.Race);
            element.Element("Ethnicity").SetValue(model.Ethnicity);

            element.Element("Team").SetValue(model.Team);
            element.Element("Cluster").SetValue(model.Cluster);
            element.Element("Household").SetValue(model.Household);

            XElement measurements = element.Element("Measurements");
            if (measurements != null)
            {
                List<XElement> measurementsToRemove = new List<XElement>();

                foreach (XElement measurement in measurements.Elements("Measurement"))
                {
                    bool found = false;
                    foreach (Measurement measurementModel in model.Measurements)
                    {
                        if (measurementModel.GlobalRecordId.Equals(measurement.Attribute("Id").Value, StringComparison.OrdinalIgnoreCase))
                        {
                            SetMeasurementXElementValue(measurementModel, measurement);
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        measurementsToRemove.Add(measurement);
                    }
                }

                foreach (XElement m in measurementsToRemove)
                {
                    m.Remove();
                }

                foreach (Measurement measurementModel in model.Measurements)
                {
                    bool found = false;
                    foreach (XElement measurement in measurements.Elements("Measurement"))
                    {
                        if (measurementModel.GlobalRecordId.Equals(measurement.Attribute("Id").Value, StringComparison.OrdinalIgnoreCase))
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        measurements.Add(CreateMeasurementXElement(measurementModel));
                    }
                }
            }
        }

        private void SetMeasurementXElementValue(Measurement model, XElement element)
        {
            if (model == null) throw new ArgumentNullException("model");
            if (element == null) throw new ArgumentNullException("element");

            element.Attribute("Id").SetValue(model.GlobalRecordId);
            element.Attribute("DateCreated").SetValue(model.DateCreated.ToString(System.Globalization.CultureInfo.InvariantCulture));
            element.Attribute("DateUpdated").SetValue(model.DateUpdated.ToString(System.Globalization.CultureInfo.InvariantCulture));

            element.Element("DateMeasurement").SetValue(model.DateMeasurement.ToString(System.Globalization.CultureInfo.InvariantCulture));
            element.Element("IsDateMeasurementEstimated").SetValue(model.IsDateMeasurementEstimated);
            element.Element("AgeDays").SetValue(model.AgeDays.ToString(System.Globalization.CultureInfo.InvariantCulture));

            element.Element("IsRecumbent").SetValue(model.IsRecumbent);
            element.Element("HasOedema").SetValue(model.HasOedema);

            element.Element("BMI").SetValue(model.BodyMassIndex.HasValue ? model.BodyMassIndex.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty);
            element.Element("Ht").SetValue(model.Height.HasValue ? model.Height.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty);
            element.Element("Wt").SetValue(model.Weight.HasValue ? model.Weight.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty);
            element.Element("Hc").SetValue(model.HeadCircumference.HasValue ? model.HeadCircumference.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty);
            element.Element("Muac").SetValue(model.MidUpperArmCircumference.HasValue ? model.MidUpperArmCircumference.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty);
            element.Element("Ssf").SetValue(model.SubscapularSkinfold.HasValue ? model.SubscapularSkinfold.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty);
            element.Element("Tsf").SetValue(model.TricepsSkinfold.HasValue ? model.TricepsSkinfold.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : String.Empty);

            element.Element("Notes").SetValue(model.Notes);
            element.Element("Location").SetValue(model.Location);
        }


        public XmlPersonRepository(string fileName, XName entityName)
            : base(fileName, entityName)
        {
        }

        protected override XElement GetParentElement()
        {
            return Document.Root.Elements("People").First();
        }

        protected override object GetEntityId(Person entity)
        {
            if (entity == null) throw new ArgumentNullException("entity");

            return entity.GlobalRecordId;
        }
    }
}
